﻿using System;
using System.Threading;
using System.Collections.Generic;
using ebay.Model;
using com.paypal.soap.api;

namespace ebay.BLL
{
    public delegate void PayPalEventHandler(object sender, EventArgs e);

    public class GetPayPalTransactionDetailsTask
    {

        class Transaction
        {
            /// <summary>
            ///   constructor
            /// </summary>
            /// <param name="ebayAccount">eBay account</param>
            /// <param name="transactionID">transaction id</param>
            public Transaction(String ebayAccount, String transactionID)
            {
                eBayAccount = ebayAccount;
                TransactionID = transactionID;
            }

            // eBay account
            public String eBayAccount;
            // transaction id
            public String TransactionID;
        }

        public GetPayPalTransactionDetailsTask()
        {
            //m_eBayUserId = eBayAccount;
            m_queue = new Queue<Transaction>();
            m_autoResetEvent = new AutoResetEvent(false);
            m_list = new List<PayPalTransactionDetails>();
        }

        public bool Start()
        {
            m_completedCount = 0;

            System.Data.DataTable table = Dal.PayPalTransactionDetailsHelper.Query();
            foreach (System.Data.DataRow row in table.Rows)
            {
                Enqueue(row["eBayUserId"] as String, row["PayPalTransactionId"] as String);
            }
            
            // initialize 5 threads
            for (int idx = 0; idx < 5; idx++)
            {
                Thread thread = new Thread(new ThreadStart(Run));
                thread.Start();
            }

            // wait for thread end
            m_autoResetEvent.WaitOne();
            Dal.PayPalTransactionDetailsHelper.WriteServer(m_list);

            return true;
        }

        public void Enqueue(String eBayAccount, String transactionID)
        {
            lock (m_queue)
            {
                m_queue.Enqueue(new Transaction(eBayAccount, transactionID));
            }
        }

        private int CompletedCount
        {
            get
            {
                lock (m_obj)
                {
                    return m_completedCount;
                }
            }
            set
            {
                lock (m_obj)
                {
                    m_completedCount = value;
                    if (m_completedCount == 5)
                    {
                        m_autoResetEvent.Set();
                    }
                }
            }
        }

        private Transaction Dequeue()
        {
            lock (m_queue)
            {
                return m_queue.Count == 0 ? null : m_queue.Dequeue();
            }
        }

        /// <summary>
        ///   thread function
        /// </summary>
        public void Run()
        {
            Transaction transaction = Dequeue();
            while (null != transaction)
            {
                GetTransactionDetails(transaction.eBayAccount, transaction.TransactionID);

                transaction = Dequeue();
            }

            CompletedCount++;
        }

        private void GetTransactionDetails(String eBayAccount, String transactionID)
        {
            int tryCount = 0;
            List<Account> accounts = Config.Instance().Accounts[eBayAccount];
            while (tryCount < 10)
            {
                foreach (Account account in accounts)
                {
                    ebay.ebayApi.PayPalAPI api = new ebay.ebayApi.PayPalAPI(account.Username, account.Password, account.Signature);

                    GetTransactionDetailsResponseType response = api.GetTransactionDetailsInfo(transactionID);

                    if (response.Ack == AckCodeType.Success)
                    {
                        BuildPayPalTransactionDetails(response, account.Usercode);
                        return;
                    }
                }

                tryCount++;
            }
        }

        private void BuildPayPalTransactionDetails(GetTransactionDetailsResponseType response, String usercode)
        {
            PayPalTransactionDetails ppDetails = new PayPalTransactionDetails();

            PaymentTransactionType ptDetails = response.PaymentTransactionDetails;
            if (null == ptDetails)
                return;

            ppDetails.ShippingCalculationMode = (ptDetails.UserSelectedOptions == null ? null : ptDetails.UserSelectedOptions.ShippingCalculationMode);

            ppDetails.InsuranceOptionSelected = (ptDetails.UserSelectedOptions == null ? null : ptDetails.UserSelectedOptions.InsuranceOptionSelected);

            ppDetails.GiftMessage = ptDetails.GiftMessage;

            ppDetails.GiftReceiptenable = ptDetails.GiftReceipt;

            ppDetails.GiftWrapName = ptDetails.GiftWrapName;

            if (null != ptDetails.GiftWrapAmount && !String.IsNullOrEmpty(ptDetails.GiftWrapAmount.Value))
                ppDetails.GiftWrapAmount = Convert.ToDecimal(ptDetails.GiftWrapAmount.Value);

            ppDetails.BuyerMarketingEmail = ptDetails.BuyerEmailOptIn;

            ppDetails.SurveyQuestion = ptDetails.SurveyQuestion;

            ppDetails.SurveyChoiceSelected = (ptDetails.SurveyChoiceSelected == null ? null : String.Join("", ptDetails.SurveyChoiceSelected));

            if (null != ptDetails.ReceiverInfo)
            {
                ppDetails.ReceiverBusiness = ptDetails.ReceiverInfo.Business;

                ppDetails.ReceiverEmail = ptDetails.ReceiverInfo.Receiver;
                
                ppDetails.ReceiverID = ptDetails.ReceiverInfo.ReceiverID;
            }

            if (null != ptDetails.PayerInfo)
            {
                ppDetails.Email = response.PaymentTransactionDetails.PayerInfo.Payer;
                
                ppDetails.PayerID = response.PaymentTransactionDetails.PayerInfo.PayerID;
                
                ppDetails.PayerStatus = response.PaymentTransactionDetails.PayerInfo.PayerStatus.ToString();
                
                ppDetails.CountryCode = response.PaymentTransactionDetails.PayerInfo.PayerCountry.ToString();
                
                ppDetails.PayerBusiness = response.PaymentTransactionDetails.PayerInfo.PayerBusiness;
                
                ppDetails.Salutation = response.PaymentTransactionDetails.PayerInfo.PayerName.Salutation;
                
                ppDetails.FirstName = response.PaymentTransactionDetails.PayerInfo.PayerName.FirstName;
                
                ppDetails.MiddleName = response.PaymentTransactionDetails.PayerInfo.PayerName.MiddleName;
                
                ppDetails.LastName = response.PaymentTransactionDetails.PayerInfo.PayerName.LastName;
                
                ppDetails.Suffix = response.PaymentTransactionDetails.PayerInfo.PayerName.Suffix;
                
                ppDetails.AddressOwner = response.PaymentTransactionDetails.PayerInfo.Address.AddressOwner.ToString();
                
                ppDetails.AddressStatus = response.PaymentTransactionDetails.PayerInfo.Address.AddressStatus.ToString();
                
                //ppDetails.ShipToSecondaryName;
                
                ppDetails.ShipToName = response.PaymentTransactionDetails.PayerInfo.Address.Name;
                
                ppDetails.ShipToStreet = response.PaymentTransactionDetails.PayerInfo.Address.Street1;
                
                //ppDetails.ShipToSecondaryAddressLine1;
                
                ppDetails.ShipToStreet2 = response.PaymentTransactionDetails.PayerInfo.Address.Street2;
                
                //ppDetails.ShipToSecondaryAddressLine2;
                ppDetails.ShipToCity = response.PaymentTransactionDetails.PayerInfo.Address.CityName;
                
                //ppDetails.ShipToSecondaryCity;
                
                ppDetails.ShipToState = response.PaymentTransactionDetails.PayerInfo.Address.StateOrProvince;
                
                //ppDetails.ShipToSecondaryState;
                
                ppDetails.ShipToZip = response.PaymentTransactionDetails.PayerInfo.Address.PostalCode;
                
                //ppDetails.ShipToSecondaryZip;
                
                ppDetails.ShipToCountryCode = response.PaymentTransactionDetails.PayerInfo.Address.Country.ToString();
                
                //ppDetails.ShipToSecondaryCountryCode;
                
                ppDetails.ShipToPhonenum = response.PaymentTransactionDetails.PayerInfo.Address.Phone;
                
                //ppDetails.ShipToSecondaryPhonenum;
            }

            if (null != ptDetails.PaymentInfo)
            {
                ppDetails.TransactionID = ptDetails.PaymentInfo.TransactionID;

                ppDetails.ParentTransactionID = ptDetails.PaymentInfo.ParentTransactionID;
                
                ppDetails.ReceiptID = ptDetails.PaymentInfo.ReceiptID;
                
                ppDetails.TransactionType = response.PaymentTransactionDetails.PaymentInfo.TransactionType.ToString();
                
                ppDetails.PaymentType = response.PaymentTransactionDetails.PaymentInfo.PaymentType.ToString();
                
                ppDetails.OrderTime = response.PaymentTransactionDetails.PaymentInfo.PaymentDate;

                if (null != ptDetails.PaymentInfo.GrossAmount && !String.IsNullOrEmpty(ptDetails.PaymentInfo.GrossAmount.Value))
                    ppDetails.AMT = Convert.ToDecimal(ptDetails.PaymentInfo.GrossAmount.Value);
                
                ppDetails.CurrencyCode = response.PaymentTransactionDetails.PaymentInfo.GrossAmount.currencyID.ToString();
                
                if (null != ptDetails.PaymentInfo.FeeAmount && !String.IsNullOrEmpty(ptDetails.PaymentInfo.FeeAmount.Value))
                    ppDetails.FeeAMT = Convert.ToDecimal(ptDetails.PaymentInfo.FeeAmount.Value);
                
                if (null != ptDetails.PaymentInfo.SettleAmount && !String.IsNullOrEmpty(ptDetails.PaymentInfo.SettleAmount.Value))
                    ppDetails.SettleAMT = Convert.ToDecimal(ptDetails.PaymentInfo.SettleAmount);

                if (null != ptDetails.PaymentInfo.TaxAmount && !String.IsNullOrEmpty(ptDetails.PaymentInfo.TaxAmount.Value))
                    ppDetails.TaxAMT = Convert.ToDecimal(ptDetails.PaymentInfo.TaxAmount.Value);

                if (!String.IsNullOrEmpty(ptDetails.PaymentInfo.ExchangeRate))
                    ppDetails.ExchangeRate = Convert.ToDecimal(ptDetails.PaymentInfo.ExchangeRate);

                ppDetails.PaymentStatus = response.PaymentTransactionDetails.PaymentInfo.PaymentStatus.ToString();
                ppDetails.PendingReason = response.PaymentTransactionDetails.PaymentInfo.PendingReason.ToString();
                ppDetails.ReasonCode = response.PaymentTransactionDetails.PaymentInfo.ReasonCode.ToString();
                ppDetails.ProtectionEligibility = response.PaymentTransactionDetails.PaymentInfo.ProtectionEligibility;
                ppDetails.ProtectionEligibilityType = response.PaymentTransactionDetails.PaymentInfo.ProtectionEligibilityType;
                //ppDetails.StoreId = response.PaymentTransactionDetails.PaymentInfo.StoreId;
                //ppDetails.TerminalId = response.PaymentTransactionDetails.PaymentInfo.TerminalId;
                ppDetails.Invnum = response.PaymentTransactionDetails.PaymentItemInfo.InvoiceID;
                ppDetails.Custom = response.PaymentTransactionDetails.PaymentItemInfo.Custom;
                ppDetails.Note = response.PaymentTransactionDetails.PaymentItemInfo.Memo;
                ppDetails.SalesTax = Convert.ToDecimal(response.PaymentTransactionDetails.PaymentItemInfo.SalesTax);
                ppDetails.BuyerID = response.PaymentTransactionDetails.PaymentItemInfo.Auction.BuyerID;
                ppDetails.ClosingDate = response.PaymentTransactionDetails.PaymentItemInfo.Auction.ClosingDate;
                ppDetails.MultiItem = response.PaymentTransactionDetails.PaymentItemInfo.Auction.multiItem;
                //ppDetails.Amount = response.PaymentTransactionDetails.PaymentItemInfo.Subscription.Terms;
                //ppDetails.Period;
                foreach (PaymentItemType item in response.PaymentTransactionDetails.PaymentItemInfo.PaymentItem)
                {
                    PaymentItem temp = new PaymentItem();
                    //paymentItem.eBayItemTXNID = item.eBayItemTXNID;
                    temp.Name = item.Name;
                    temp.Number = item.Number;
                    temp.Qty = item.Quantity;
                    //temp.CouponID = item;
                    //temp.CouponAmount;
                    //temp.CouponAmountCurrency;
                    // temp.LoyaltyCarddisCountAmount;
                    // temp.LoyaltyCarddisCountCurrency;
                    if (null != item.Amount && !String.IsNullOrEmpty(item.Amount.Value))
                        temp.AMT = Convert.ToDecimal(item.Amount.Value);

                    if (null != item.Options)
                    {
                        temp.Options = new ebay.Model.Option[item.Options.Length];
                        for (int idx = 0; idx < temp.Options.Length; idx++)
                        {
                            Option option = new Option();
                            option.Name = item.Options[idx].name;
                            option.Value = item.Options[idx].value;

                            temp.Options[idx] = option;
                        }
                    }

                    temp.ShippingAMT = Convert.ToDecimal(item.ShippingAmount);
                    temp.HandlingAMT = Convert.ToDecimal(item.HandlingAmount);

                    ppDetails.ShippingAndHandlingAMT += (temp.ShippingAMT + temp.HandlingAMT);
                }

            }

            ppDetails.Usercode = usercode;
            // to check if exists
            //  ppDetails.TimeStamp;
            lock (m_list)
            {
                m_list.Add(ppDetails);
            }
        }

        private Queue<Transaction> m_queue;
        private List<PayPalTransactionDetails> m_list;
        private int m_completedCount;
        //private String m_eBayUserId;
        private AutoResetEvent m_autoResetEvent;
        private object m_obj = new object();
    }
}
